/* global BODYPART_COST MAX_CREEP_SIZE TOUGH ATTACK RANGED_ATTACK HEAL */

export default class SpawnRole {
	/**
	 * Adds spawn options for the given room.
	 *
	 * @param {Room} room
	 *   The room to add spawn options for.
	 */
	getSpawnOptions(room: Room): SpawnOption[] {
		return [];
	}

	/**
	 * Gets the body of a creep to be spawned.
	 *
	 * @param {Room} room
	 *   The room to add spawn options for.
	 * @param {Object} option
	 *   The spawn option for which to generate the body.
	 *
	 * @return {string[]}
	 *   A list of body parts the new creep should consist of.
	 */
	getCreepBody(room: Room, option: SpawnOption): BodyPartConstant[] {
		return [];
	}

	/**
	 * Gets which boosts to use on a new creep.
	 *
	 * @param {Room} room
	 *   The room to add spawn options for.
	 * @param {Object} option
	 *   The spawn option for which to generate the body.
	 * @param {string[]} body
	 *   The body generated for this creep.
	 *
	 * @return {Object}
	 *   The boost compound to use keyed by body part type.
	 */
	getCreepBoosts(room: Room, option: SpawnOption, body: string[]): Record<string, ResourceConstant> {
		return null;
	}

	/**
	 * Gets memory for a new creep.
	 *
	 * @param {Room} room
	 *   The room to add spawn options for.
	 * @param {Object} option
	 *   The spawn option for which to generate the body.
	 *
	 * @return {Object}
	 *   The newly spawned creep's initial memory.
	 */
	getCreepMemory(room: Room, option?: SpawnOption): CreepMemory {
		return {};
	}

	/**
	 * Act when a creep belonging to this spawn role is successfully spawning.
	 *
	 * @param {Room} room
	 *   The room the creep is spawned in.
	 * @param {Object} option
	 *   The spawn option which caused the spawning.
	 * @param {string[]} body
	 *   The body generated for this creep.
	 * @param {string} name
	 *   The name of the new creep.
	 */
	onSpawn(room: Room, option: SpawnOption, body: BodyPartConstant[], name: string) {}

	/**
	 * Calculates the best available boost for a body part to use.
	 *
	 * @param {Room} room
	 *   The room to add spawn options for.
	 * @param {String[]} body
	 *   The body generated for this creep.
	 * @param {String} partType
	 *   The body part type to apply boosts to.
	 * @param {String} boostType
	 *   The type of boost to use.
	 *
	 * @return {Object}
	 *   The boost compound to use keyed by body part type.
	 */
	generateCreepBoosts(room: Room, body: BodyPartConstant[], partType: BodyPartConstant, boostType: string, maxTier?: number): Partial<Record<string, ResourceConstant>> {
		if (!room.boostManager.canSpawnBoostedCreeps()) return {};

		const availableBoosts = room.boostManager.getAvailableBoosts(boostType);
		const numberAffectedParts = _.countBy(body)[partType] || 0;
		let bestBoost: ResourceConstant;
		let resourceType: ResourceConstant;
		for (resourceType in availableBoosts) {
			if (availableBoosts[resourceType].available < numberAffectedParts) continue;
			if (maxTier && resourceType.length > maxTier) continue;

			if (!bestBoost || availableBoosts[resourceType].effect > availableBoosts[bestBoost].effect) {
				bestBoost = resourceType;
			}
		}

		if (!bestBoost) return {};

		return {
			[partType]: bestBoost,
		};
	}

	/**
	 * Calculates the cost of a creep body array.
	 *
	 * @param {String[]} body
	 *   A creep body.
	 *
	 * @return {number}
	 *   The energy cost of the provided body.
	 */
	calculateBodyCost(body: BodyPartConstant[]): number {
		return _.reduce(body, (sum, part) => sum + BODYPART_COST[part], 0);
	}
}
